package com.alibaba.citrus.cr.common.log;

import com.alibaba.citrus.cr.common.annotation.OrderRedisLock;
import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.common.exception.RepositoryException;
import com.alibaba.citrus.cr.common.lock.RedisLock;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.cz.base.tool.result.Results;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author zhangxiaorui
 * @ClassName OrderRedisLockAspect
 * @description: TODO
 * @date 2023/04/21 10:48
 * @version: 1.0
 */
@Aspect
@Component
public class OrderRedisLockHandler {
    private static final Log log = Log.getLogger(OrderRedisLockHandler.class);

    @Pointcut("@annotation(com.alibaba.citrus.cr.common.annotation.OrderRedisLock)")
    public void serviceAspect() {
    }

    /**
     * 获取注解参数，记录日志
     *
     * @param joinPoint 切入点参数
     */
    @Around(value = "serviceAspect()")
    public Object doService(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        String targetName = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        MethodSignature methodSignature = (MethodSignature)signature;
        Method targetMethod = methodSignature.getMethod();

        OrderRedisLock annotation = targetMethod.getAnnotation(OrderRedisLock.class);
        String customLockCondition = annotation.customLockCondition();
        if (StringUtils.isBlank(customLockCondition)) {
            throw new FacadeException(ErrorMessage.code("OC-00-000-01-99-003"));
        }
        String redisKey = annotation.redisLockPrefix() + customLockCondition;
        log.info(targetName + "." + methodName + "_预先生成的RedisKey:{}", redisKey);
        try (RedisLock lock = new RedisLock("REDIS_CACHE", redisKey, annotation.waitTime(), annotation.holdTime())) {
            boolean locked = lock.lock();
            if (!locked) {
                log.error(targetName + "#" + methodName + ".getLock.fail RedisKey=" + redisKey);
                return Results.fail("OC-00-000-01-99-002", "分布式锁获取失败");
            }
            log.info(targetName + "." + methodName + "_成功获取到redis锁:{}", redisKey);
            // 方法执行
            return joinPoint.proceed();
        } catch (FacadeException | RepositoryException e) {
            log.error(targetName + "#" + methodName + "_fail ", e);
            throw new FacadeException(e.getErrorCode(), e.getErrorMessage());
        } catch (Throwable throwable) {
            log.error(targetName + "#" + methodName + "_fail ", throwable);
            throw new FacadeException(ErrorMessage.code("OC-00-000-01-99-001"));
        }
    }
}
